package org.ejde.sciencelogs;

import java.awt.Font;
import java.io.IOException;
import java.util.Collection;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.MultiUserChat;

/**
 * This class contains the attributes and behaviors for the
 * XMPP-base client.
 *  
 * @author Eric Martin
 * @version 0.1
 */
public class smackClient implements MessageListener {
	
	/**
	 * The XMPPConnection object handles the connection
	 * with the XMPP server.
	 */
	private XMPPConnection connection;
	
	/**
	 * The smackChatWindow handles the event monitor
	 * window.
	 */
	private smackChatWindow chatWindow;
	
	/**
	 * The Name/IP address of the XMPP server
	 */
	private String server;
	
	/**
	 * The network port of the XMPP server.
	 */
	private int serverport;
	
	/**
	 * Flag that determines if the XMPP connection should
	 * run in DEBUG mode.
	 */
	private boolean debug;
	
	/**
	 * The name of the Multi-User Chatroom (MUC).
	 */
	private MultiUserChat muc;
	
	/**
	 * The username to use to connect to the XMPP server. 
	 */
	private String username;
	
	/**
	 * The password to use to connect to the XMPP server.
	 */
	private String password;
	
	/**
	 * The nickname to use for the user connecting to the
	 * XMPP server.
	 */
	private String nickname;
	
	/**
	 * Flag used to determine if the client is connected to
	 * the XMPP server.
	 */
	private boolean loggedin = false;

	// GUI components to interact with
	/**
	 * The roster list for the XMPP Server
	 */
	private smackUserList smackuserlist;
	
	/**
	 * The JPanel that displays the stats for the XMPP
	 * client.
	 */
	private smackStatPanel smackstatpanel;

	/**
	 * Get the roster from the XMPP server.
	 * 
	 * @return Roster roster of currently online contacts
	 * @see org.jivesoftware.smack.XMPPConnection#getRoster()
	 */
	public Roster getRoster() {
		return connection.getRoster();
	}

	/**
	 * Get method return the username as a string. 
	 * 
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * Set the username to use to connect to the XMPP
	 * server.
	 * 
	 * @param username
	 *            the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * Get method return the password used to connect to
	 * the XMPP server.
	 * 
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * Set the password to use when connecting to the
	 * XMPP server.
	 * 
	 * @param password
	 *            the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the nickname
	 */
	public String getNickname() {
		return nickname;
	}

	/**
	 * Set the nickname to use for the user connecting to
	 * the XMPP server.
	 * 
	 * @param nickname
	 *            the nickname to set
	 */
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	/**
	 * Login to the XMPP server using the provided username
	 * and password.
	 * 
	 * @param userName username to use to connect to the
	 * server. 
	 * @param password password to use to connect to the
	 * server.
	 * @throws XMPPException thrown if there is a problem
	 * connecting to the XMPP server.
	 * @throws IOException thrown if there is a network I/O
	 * problem.
	 */
	public void login(String userName, String password) throws XMPPException,
			IOException {

		connection.connect();
		connection.login(userName, password);
	}

	/**
	 * Join the Mutli-User Chatroom using the provided MUC
	 * room name.
	 * @param room the name of the MUC room to connect to.
	 * @return boolean flag designating it the client
	 * successfully connected to the MUC.  True=Success.
	 */
	public boolean joinMUC(String room) {
		this.muc = new MultiUserChat(this.connection, room);
		this.startChatWindow();

		try {
			this.muc.join(this.nickname);
			muc.addMessageListener(this.chatWindow);
		} catch (XMPPException e) {
			e.printStackTrace();
			return false;
		}
		return true;

	}

	/**
	 * Join the MUC room based using the supplied nickname.
	 * 
	 * @param nickname
	 * @throws XMPPException
	 * @see org.jivesoftware.smackx.muc.MultiUserChat#join(java.lang.String)
	 */
	public void join(String nickname) throws XMPPException {
		muc.join(nickname);
	}

	// Removed for multiuserchat setup.
	// public void sendMessage(String message, String to) throws XMPPException {
	// Chat chat = connection.getChatManager().createChat(to, this);
	// chat.sendMessage(message);
	// }

	/**
	 * Submits the supplied string as a message to the MUC.
	 * @param text the message to submit.
	 * @throws XMPPException thown if there is a problem
	 * connecting with the XMPP server.
	 * @see org.jivesoftware.smackx.muc.MultiUserChat#sendMessage(java.lang.String)
	 */
	public void sendMessage(String text) throws XMPPException {
		muc.sendMessage(text);

	}

	/**
	 * Handles the event counter for the stats panel.
	 */
	public void increaseEventCount() {
		if (this.smackstatpanel != null) {
			this.smackstatpanel.incrementMessages();
		}
	}

	/**
	 * Retrieve the buddy list for the XMPP server. 
	 */
	public void displayBuddyList() {
		Roster roster = connection.getRoster();
		Collection<RosterEntry> entries = roster.getEntries();
	}

	/**
	 * Disconnect from the XMPP server.
	 */
	public void disconnect() {
		connection.disconnect();
		if (this.loggedin) {
			this.stopChatWindow();
		}
	}

	/**
	 * Process incomming messages from the MUC Chatroom.
	 */
	public void processMessage(Chat chat, Message message) {
		if (message.getType() == Message.Type.chat)
			System.out.println(chat.getParticipant() + " says: "
					+ message.getBody());
	}

	/**
	 * Constructor method. Create a blank the XMPP Client.
	 */
	public smackClient() {
		super();
	}

	/**
	 * Constructor method.  Create a XMPP client based on
	 * the supplied information.
	 * 
	 * @param server set the name/IP address of the XMPP
	 * server to use.
	 * @param serverport set the port to use to connect to the
	 * XMPP server.
	 * @param debug set the boolean flag for running the
	 * client in debug mode.
	 */
	public smackClient(String server, int serverport, boolean debug) {
		super();
		this.server = server;
		this.serverport = serverport;
		this.debug = debug;

		initiateConnection();
	}

	/**
	 * Initialized the XMPPConnection object.
	 */
	public void initiateConnection() {

		XMPPConnection.DEBUG_ENABLED = this.debug;

		ConnectionConfiguration config = new ConnectionConfiguration(server,
				serverport);
		this.connection = new XMPPConnection(config);

	}

	/**
	 * Create a manage the login dialog window for the XMPP
	 * client.
	 * @return boolean flag designating if the connection
	 * was successful.  True=success.
	 */
	public boolean loginWindow() {

		String newloginname;
		String newpassword;
		boolean selectedCB;

		JLabel label_welcome = new JLabel("<html>Welcome to Periscope<br><br>");
		label_welcome.setFont(new Font("SansSerif", Font.PLAIN, 18));

		JLabel label_error = new JLabel("");
		label_error.setFont(new Font("SansSerif", Font.PLAIN, 12));
		// Components related to "login" field
		JLabel label_loginname = new JLabel("Enter your login name:");
		JTextField loginname = new JTextField(15);
		// loginname.setText("EnterLoginNameHere"); // Pre-set some text

		// Components related to "password" field
		JLabel label_password = new JLabel("Enter your password:");
		JPasswordField password = new JPasswordField();
		// password.setEchoChar('@'); // Sets @ as masking character
		// password.setEchoChar('\000'); // Turns off masking

		JCheckBox rememberCB = new JCheckBox("Remember me");
		JLabel label_server = new JLabel("<html><br>Server: " + this.server
				+ ":" + this.serverport);

		Object[] array = { label_welcome, label_error, label_loginname,
				loginname, label_password, password,
				// rememberCB,
				label_server };

		boolean lastres = false;
		this.loggedin = false;

		while (!lastres) {
			int res = JOptionPane.showConfirmDialog(null, array, "Login",
					JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

			// User hit OK
			if (res == JOptionPane.OK_OPTION) {
				// System.out.println( "OK_OPTION" );
				lastres = true;

				// Output data in "login" field, if any
				newloginname = loginname.getText();
				// System.out.println( "newloginname: " + newloginname );

				// Output data in "password" field, if any
				newpassword = new String(password.getPassword());
				// System.out.println( "newpassword: " + newpassword );

				// Output state of "remember me" check box
				selectedCB = rememberCB.isSelected();
				// System.out.println( "selectedCB: " + selectedCB );

				// Attempt to login
				try {
					login(newloginname, newpassword);
					loggedin = true;
					this.username = newloginname;
					this.password = newpassword;
					this.nickname = this.username;
				} catch (XMPPException e) {
					lastres = false;
					loggedin = false;

					label_error
							.setText("<html><FONT COLOR=RED>Login error(s):  "
									+ e.getMessage() + "</FONT></html>");
					this.disconnect();
				} catch (IOException ioerr) {
					lastres = false;
				}
			}

			// User hit CANCEL
			if (res == JOptionPane.CANCEL_OPTION) {
				// System.out.println( "CANCEL_OPTION" );
				lastres = true;
				loggedin = false;
			}

			// User closed the window without hitting any button
			if (res == JOptionPane.CLOSED_OPTION) {
				// System.out.println( "CLOSED_OPTION" );
				lastres = true;
				loggedin = false;
			}

		}

		return loggedin;

	}

	/**
	 * Start the XMPP chat monitor window.
	 */
	public void startChatWindow() {
		chatWindow = new smackChatWindow();

	}

	/**
	 * Destroy the XMPP chat monitor window.
	 */
	public void stopChatWindow() {
		chatWindow.dispose();
	}

	/**
	 * Get method.  Return the name/IP address of the XMPP
	 * server.
	 * @return the name/IP address of the XMPP server.
	 */
	public String getServer() {
		return server;
	}

	/**
	 * Set the name/IP address of the XMPP server.
	 * 
	 * @param server
	 *            the server to set
	 */
	public void setServer(String server) {
		this.server = server;
	}

	/**
	 * Get method.  Return the port number for the XMPP
	 * server.
	 * 
	 * @return the XMPP server port
	 */
	public int getServerport() {
		return serverport;
	}

	/**
	 * Set the port number for the XMPP server.
	 * 
	 * @param serverport
	 *            the serverport to set
	 */
	public void setServerport(int serverport) {
		this.serverport = serverport;
	}

	/**
	 * Get method.  Return the debug boolean flag.
	 * 
	 * @return the boolen debug flag.
	 */
	public boolean isDebug() {
		return debug;
	}

	/**
	 * Set the boolean debug flag.
	 * 
	 * @param debug
	 *            the boolean debug flag.
	 */
	public void setDebug(boolean debug) {
		this.debug = debug;
	}

	/**
	 * @return the loggedin
	 */
	public boolean isLoggedin() {
		return loggedin;
	}

	/**
	 * Set the user list for the XMPP client.
	 * 
	 * @param smackuserlist
	 *            the smackuserlist to set
	 */
	public void setSmackuserlist(smackUserList smackuserlist) {
		this.smackuserlist = smackuserlist;
	}

	/**
	 * Set the XMPP Client stats page.
	 * @param smackstatpanel
	 *            the smackstatpanel to set
	 */
	public void setSmackstatpanel(smackStatPanel smackstatpanel) {
		this.smackstatpanel = smackstatpanel;
	}

	/**
	 * Get method.  Get the XMPP client user list.
	 * 
	 * @return the smackuserlist
	 */
	public smackUserList getSmackuserlist() {
		return smackuserlist;
	}

	/**
	 * Get method.  Return the XMPP stats panel.
	 * 
	 * @return the smackstatpanel
	 */
	public smackStatPanel getSmackstatpanel() {
		return smackstatpanel;
	}

	/**
	 * Refresh the JComponents related to the XMPP Client.
	 */
	public void refreshGUIcomponents() {
		if (this.smackstatpanel != null) {

		}

		if (this.smackuserlist != null) {
			smackuserlist.populateRoster();
			// System.out.println("in refresh");
		}
		// else System.out.println("smackuserlist is null");
	}

}
